/*
//              INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license  agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in  accordance  with the terms of that agreement.
//    Copyright (c) 2006-2007 Intel Corporation. All Rights Reserved.
//
*/
#include "umc_defs.h"
#if defined (UMC_ENABLE_DV_VIDEO_ENCODER)

#include "umc_dv_video_encoder.h"
#include "umc_video_data.h"
#include "umc_dv_enc_segment_writer.h"
#include "umc_dv_enc_segment_compressor.h"
#include "umc_dv_enc_compressor_def.h"
#include "umc_dv_enc_dvsd_ntsc_segment_reader.h"
#include "umc_dv_enc_dvsd_pal_segment_reader.h"

namespace UMC
{

DVVideoEncoder::DVVideoEncoder(void):
    m_pDVWriter(NULL),
    m_pSCompressor(NULL),
    m_pSReader(NULL),
    m_bIsInit(false)
{
}

DVVideoEncoder::~DVVideoEncoder(void)
{
    Close();
}

Status DVVideoEncoder::Reset()
{
    return UMC_OK;
}

Status DVVideoEncoder::SetParams(BaseCodecParams* /*pParams*/)
{
    return UMC_OK;
}

Status DVVideoEncoder::Init(BaseCodecParams* pBaseParams)
{
    VideoEncoderParams *pParams = DynamicCast<VideoEncoderParams> (pBaseParams);

    if (pParams == NULL)
        return UMC_ERR_NULL_PTR;

    if (m_bIsInit)
        Close();

    if( pParams->info.clip_info.width != 720 || (pParams->info.clip_info.height != 576 && pParams->info.clip_info.height != 480) )
      return UMC_ERR_INVALID_STREAM;

    if(UMC_OK != BaseCodec::Init(pBaseParams))
        return UMC_ERR_INIT;

    //init Huffman Tables
    //377 ENCODE_ELEMENT entries
    //63 Ipp16s elements in TableMaxAmpOnRun table
    //62 (ENCODE_ELEMENT*) entries for encode table
    //4096 - reserved for alignment
    newHuffmanTablesBuffer = ippsMalloc_8u(377 * 4 + 63 * 2 + 62 * 4 + 4096);
    InitHuffmanTables(newHuffmanTablesBuffer);

    m_Params = *pParams;
    m_Params.info.stream_type = DIGITAL_VIDEO_SD;
    m_iMaxI = (480 == m_Params.info.clip_info.height) ? 10 : 12;

    // create DV segment writer
    m_pDVWriter = new DVSegmentWriter;
    if (NULL == m_pDVWriter)
        return UMC_ERR_ALLOC ;
    if (m_pDVWriter->InitWriter( (480 == pParams->info.clip_info.height) ? 0 : 1, 0 /*DVSD*/))
        return UMC_ERR_INIT;

    // create segment compressor
    m_pSCompressor = new SegmentCompressor;
    if (NULL == m_pSCompressor)
        return UMC_ERR_ALLOC ;
    if (m_pSCompressor->InitCompressor(6, m_pMemoryAllocator))
        return UMC_ERR_INIT;

    // create segment reader
    if (480 == m_Params.info.clip_info.height)
        m_pSReader = new DVSD_NTSC_SegmentReader(10);
    else if(576 == m_Params.info.clip_info.height)
        m_pSReader = new DVSD_PAL_SegmentReader;
    if (NULL == m_pSReader)
        return UMC_ERR_INIT;

    m_bIsInit = true;
    return UMC_OK;
}

Status DVVideoEncoder::GetInfo(BaseCodecParams* pInfo)
{
    VideoEncoderParams* pEncoderInfo = DynamicCast<VideoEncoderParams, BaseCodecParams>(pInfo);

    if(pEncoderInfo)
    {
        *pEncoderInfo = m_Params;
    }
    else if(pInfo)
    {
        VideoEncoderParams* pGenInfo = DynamicCast<VideoEncoderParams, BaseCodecParams>(pInfo);
        if(pGenInfo) {
            *pGenInfo = m_Params;
        } else {
            return UMC_ERR_INVALID_STREAM;
        }
    } else {
        return UMC_ERR_NULL_PTR;
    }

    return UMC_OK;
}

Status DVVideoEncoder::Close()
{
    if (!m_bIsInit)
        return UMC_ERR_NOT_INITIALIZED;

    //BaseCodec::Close();

    if (newHuffmanTablesBuffer)
        ippsFree(newHuffmanTablesBuffer);

    if (m_pDVWriter)
        delete m_pDVWriter;

    if (m_pSCompressor)
        delete m_pSCompressor;

    if (m_pSReader)
        delete m_pSReader;

    m_bIsInit = false;
    return UMC_OK;
}

Status DVVideoEncoder::GetFrame(MediaData *pVideoDataIn, MediaData *pEncodedFrame)
{
    Ipp8u DIFSeqNum;
    Ipp16s VSegmentNum;
    DV_SEGMENT *lpDVSegment;
    V_SEGMENT *lpVSegment;

    if (!m_bIsInit)
        return UMC_ERR_NOT_INITIALIZED;

    VideoData* pSrcFrame = DynamicCast<VideoData> (pVideoDataIn);
    if (!pSrcFrame || !pEncodedFrame)
        return UMC_ERR_NOT_ENOUGH_DATA;

    if(pEncodedFrame->GetBufferSize() < ((m_iMaxI == 10) ? 120000u : 144000u))
        return UMC_ERR_NOT_ENOUGH_BUFFER;

    m_pDVWriter->m_pDest = (Ipp8u *) pEncodedFrame->GetDataPointer();

    m_pSReader->m_lpSourceFrame = pSrcFrame;

    m_pSCompressor->LockWorkBuffers();
    lpVSegment = &(m_pSCompressor->m_VSegment);

    for (DIFSeqNum = 0; DIFSeqNum < m_iMaxI; DIFSeqNum++)
    {
        m_pDVWriter->StartDIFSequence(DIFSeqNum, 0 /*FSC*/);
        for (VSegmentNum = 0; VSegmentNum < 27; VSegmentNum++)
        {
            m_pDVWriter->SetDVSegment(&lpDVSegment);
            m_pSReader->ReadSegment(lpVSegment, DIFSeqNum, VSegmentNum);
            m_pSCompressor->CompressSegment(lpDVSegment);
        }
    }
    m_pSCompressor->UnlockWorkBuffers();

    pEncodedFrame->SetDataSize((m_iMaxI == 10) ? 120000u : 144000u);

    return UMC_OK;
}

}// namespace UMC

#endif //(UMC_ENABLE_DV_VIDEO_ENCODER)
